/*
 * @Author: LVGRAPE
 * @Date: 2023-10-18 18:22:07
 * @LastEditTime: 2023-10-23 11:31:19
 * @LastEditors: LVGRAPE
 * @Description:
 * @FilePath: \rt_ZINO_RC_PRO\libraries\f415\virtual_comport\virtual_comport.c
 * 要啥没啥，爱咋咋的
 */

#include "usb_conf.h"
#include "usb_core.h"
#include "usbd_int.h"
#include "cdc_class.h"
#include "cdc_desc.h"
#include "rtthread.h"
#include "drv_common.h"

 /** @addtogroup AT32F415_periph_examples
   * @{
   */

   /** @addtogroup 415_USB_device_virtual_comport USB_device_virtual_comport
     * @{
     */

     /* usb global struct define */
otg_core_type otg_core_struct;
uint8_t usb_buffer[256];
void usb_clock48m_select(usb_clk48_s clk_s);
void usb_gpio_config(void);
void usb_low_power_wakeup_config(void);

/* usart global struct define */
extern linecoding_type linecoding;
void usb_usart_config(linecoding_type linecoding);
void usart_gpio_config(void);
#define  usart_buffer_size  2048
uint8_t usart_rx_buffer[usart_buffer_size];
uint16_t hw_usart_rx_index = 0;
uint16_t hw_usart_read_index = 0;
uint16_t usart_rx_data_len = 0;
uint16_t ov_cnt = 0;
void usart_send_data(uint8_t* send_data, uint16_t len);
uint16_t usart_receive_data(void);

/**
  * @brief  main function.
  * @param  none
  * @retval none
  */
void vcom_thread_entry(void* arg)
{
    uint16_t data_len;

    uint32_t timeout;

    uint8_t send_zero_packet = 0;

    // nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);

    // system_clock_config();

    // at32_board_init();

    /* usart gpio config */
    // usart_gpio_config();

    /* hardware usart config: usart2 */
    // usb_usart_config(linecoding);

    /* usb gpio config */
    // usb_gpio_config();

#ifdef USB_LOW_POWER_WAKUP
    usb_low_power_wakeup_config();
#endif

    /* enable otgfs clock */
    crm_periph_clock_enable(OTG_CLOCK, TRUE);
    /* select usb 48m clcok source */
    usb_clock48m_select(USB_CLK_HEXT);

    /* enable otgfs irq */
    nvic_irq_enable(OTG_IRQ, 0, 0);
    /* init usb */
    usbd_init(&otg_core_struct,
        USB_FULL_SPEED_CORE_ID,
        USB_ID,
        &cdc_class_handler,
        &cdc_desc_handler);

    rt_kprintf("usbd init done\n");

    while (1)
    {
        /* get usb vcp receive data */
        data_len = usb_vcp_get_rxdata(&otg_core_struct.dev, usb_buffer);

        /* send data to hardware usart */
        if (data_len > 0)
        {
            // usart_send_data(usb_buffer, data_len);
            rt_kprintf("usb_vcp_get_rxdata:%s\n", usb_buffer);
        }

        /* if hardware usart received data,usb send data to host */
        // usart_rx_data_len = usart_receive_data();
        usart_rx_data_len = 0;
        if (usart_rx_data_len || send_zero_packet == 1)
        {
            if (usart_rx_data_len > 0)
                send_zero_packet = 1;

            if (usart_rx_data_len == 0)
                send_zero_packet = 0;

            timeout = 50000;

            if ((hw_usart_read_index + usart_rx_data_len) < usart_buffer_size)
            {
                do
                {
                    /* send data to host */
                    if (usb_vcp_send_data(&otg_core_struct.dev, &usart_rx_buffer[hw_usart_read_index], usart_rx_data_len) == SUCCESS)
                    {
                        hw_usart_read_index = hw_usart_read_index + usart_rx_data_len;

                        break;
                    }
                    rt_thread_delay(1);
                } while (timeout--);

            }
            /* process the fifo overflow */
            else
            {
                do
                {
                    /* send data to host */
                    if (usb_vcp_send_data(&otg_core_struct.dev, &usart_rx_buffer[hw_usart_read_index], usart_buffer_size - hw_usart_read_index) == SUCCESS)
                    {
                        /* get fifo overflow data count */
                        ov_cnt = usart_rx_data_len - (usart_buffer_size - hw_usart_read_index);
                        hw_usart_read_index = 0;
                        break;
                    }
                    rt_thread_delay(1);
                } while (timeout--);
                timeout = 50000;
                do
                {
                    /* send data to host */
                    if (usb_vcp_send_data(&otg_core_struct.dev, &usart_rx_buffer[hw_usart_read_index], ov_cnt) == SUCCESS)
                    {
                        hw_usart_read_index = ov_cnt;
                        break;
                    }
                    rt_thread_delay(1);
                } while (timeout--);
            }
        }
        rt_thread_delay(10);
    }
}
int launch_virtual_comport()
{
    rt_thread_t tid;
    tid = rt_thread_create("vcom",
        vcom_thread_entry,
        RT_NULL,
        1024,
        10,
        10);
    if (tid != RT_NULL)
    {
        rt_thread_startup(tid);
        rt_kprintf("launch_virtual_comport");
        return RT_EOK;
    }
    return -1;
}
#include "zino.h"
ZINO_APP_EXPORT(launch_virtual_comport);




/**
  * @brief  usb 48M clock select
  * @param  clk_s:USB_CLK_HICK, USB_CLK_HEXT
  * @retval none
  */
void usb_clock48m_select(usb_clk48_s clk_s)
{
    switch (system_core_clock)
    {
        /* 48MHz */
    case 48000000:
        crm_usb_clock_div_set(CRM_USB_DIV_1);
        break;

        /* 72MHz */
    case 72000000:
        crm_usb_clock_div_set(CRM_USB_DIV_1_5);
        break;

        /* 96MHz */
    case 96000000:
        crm_usb_clock_div_set(CRM_USB_DIV_2);
        break;

        /* 120MHz */
    case 120000000:
        crm_usb_clock_div_set(CRM_USB_DIV_2_5);
        break;

        /* 144MHz */
    case 144000000:
        crm_usb_clock_div_set(CRM_USB_DIV_3);
        break;

    default:
        break;
    }
}

/**
  * @brief  this function config gpio.
  * @param  none
  * @retval none
  */
void usb_gpio_config(void)
{
    gpio_init_type gpio_init_struct;

    crm_periph_clock_enable(OTG_PIN_GPIO_CLOCK, TRUE);
    gpio_default_para_init(&gpio_init_struct);

    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;

#ifdef USB_SOF_OUTPUT_ENABLE
    crm_periph_clock_enable(OTG_PIN_SOF_GPIO_CLOCK, TRUE);
    gpio_init_struct.gpio_pins = OTG_PIN_SOF;
    gpio_init(OTG_PIN_SOF_GPIO, &gpio_init_struct);
#endif

    /* otgfs use vbus pin */
#ifndef USB_VBUS_IGNORE
    gpio_init_struct.gpio_pins = OTG_PIN_VBUS;
    gpio_init_struct.gpio_pull = GPIO_PULL_DOWN;
    gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
    gpio_init(OTG_PIN_GPIO, &gpio_init_struct);
#endif


}
#ifdef USB_LOW_POWER_WAKUP
/**
  * @brief  usb low power wakeup interrupt config
  * @param  none
  * @retval none
  */
void usb_low_power_wakeup_config(void)
{
    exint_init_type exint_init_struct;

    exint_default_para_init(&exint_init_struct);

    exint_init_struct.line_enable = TRUE;
    exint_init_struct.line_mode = EXINT_LINE_INTERRUPUT;
    exint_init_struct.line_select = OTG_WKUP_EXINT_LINE;
    exint_init_struct.line_polarity = EXINT_TRIGGER_RISING_EDGE;
    exint_init(&exint_init_struct);

    nvic_irq_enable(OTG_WKUP_IRQ, 0, 0);
}

/**
  * @brief  this function handles otgfs wakup interrupt.
  * @param  none
  * @retval none
  */
void OTG_WKUP_HANDLER(void)
{
    exint_flag_clear(OTG_WKUP_EXINT_LINE);
}

#endif

/**
  * @brief  this function handles otgfs interrupt.
  * @param  none
  * @retval none
  */
void OTG_IRQ_HANDLER(void)
{
    usbd_irq_handler(&otg_core_struct);
}

/**
  * @brief  usb delay millisecond function.
  * @param  ms: number of millisecond delay
  * @retval none
  */
void usb_delay_ms(uint32_t ms)
{
    /* user can define self delay function */
    // delay_ms(ms);
    rt_thread_mdelay(ms);
}

/**
  * @brief  usb delay microsecond function.
  * @param  us: number of microsecond delay
  * @retval none
  */
void usb_delay_us(uint32_t us)
{
    rt_hw_us_delay(us);
    // delay_us(us);
    // rt_thread_delay(us);
}
/**
  * @brief  this function handles usart2  and linecoding config.
  * @param  linecoding: linecoding value
  * @retval none
  */
void usb_usart_config( linecoding_type linecoding)
{
//   usart_stop_bit_num_type usart_stop_bit;
//   usart_data_bit_num_type usart_data_bit;
//   usart_parity_selection_type usart_parity_select;

//   /* enable the usart2 and gpio clock */
//   crm_periph_clock_enable(CRM_USART2_PERIPH_CLOCK, FALSE);
//   crm_periph_clock_enable(CRM_USART2_PERIPH_CLOCK, TRUE);

//   /* stop bit */
//   switch(linecoding.format)
//   {
//     case 0x0:
//       usart_stop_bit = USART_STOP_1_BIT;
//       break;
// 	/* to be used when transmitting and receiving data in smartcard mode */
//     case 0x1:
//       usart_stop_bit = USART_STOP_1_5_BIT;
//       break;
//     case 0x2:
//       usart_stop_bit = USART_STOP_2_BIT;
//       break;
//     default :
//       break;
//   }
//   /* data bits */
//   switch(linecoding.data)
//   {
//     /* hardware usart not support data bits for 5/6 */
//     case 0x5:
//     case 0x6:
//     case 0x7:
//       break;
//     case 0x8:
//       usart_data_bit = USART_DATA_8BITS;
//       break;
//     /* hardware usart not support data bits for 16 */
//     case 0x10:
//       break;
//     default :
//       break;
//   }
//   /* parity */
//   switch(linecoding.parity)
//   {
//     case 0x0:
//       usart_parity_select = USART_PARITY_NONE;
//       break;
//     case 0x1:
//       usart_parity_select = USART_PARITY_ODD;
//       break;
//     case 0x2:
//       usart_parity_select = USART_PARITY_EVEN;
//       break;
//     /* hardware usart not support partiy for mark and space */
//     case 0x3:
//     case 0x4:
//       break;
//     default :
//       break;
//   }

//   nvic_irq_enable(USART2_IRQn, 0, 0);

//   /* configure usart2 param */
//   usart_init(USART2, linecoding.bitrate, usart_data_bit, usart_stop_bit);
//   usart_parity_selection_config(USART2, usart_parity_select);
//   usart_transmitter_enable(USART2, TRUE);
//   usart_receiver_enable(USART2, TRUE);

//   /* enable usart2 interrupt */
//   usart_interrupt_enable(USART2, USART_RDBF_INT, TRUE);
//   usart_enable(USART2, TRUE);
}
/**
  * @}
  */

  /**
    * @}
    */
